Micron Document
🎖️GitЯра🎖️


Displaying Raw • Download

core/takserver/src/jvmAndroidMain/kotlin/org/meshtastic/core/takserver/TAKServerJvm.kt fix/qr-error-correction (7b45f84f) Text, 12.31 KB

T8b949e/*
* Copyright (c) 2026 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
Tf0883e@fileTb4b4b4:Te6edf3SuppressTb4b4b4(Ta5d6ff"Ta5d6ffTooGenericExceptionCaughtTa5d6ff"Tb4b4b4)

Tff7b72package T7ee787org.meshtastic.core.takserver

Tff7b72import T7ee787co.touchlab.kermit.Logger
Tff7b72import T7ee787kotlinx.coroutines.CancellationException
Tff7b72import T7ee787kotlinx.coroutines.CoroutineScope
Tff7b72import T7ee787kotlinx.coroutines.Job
Tff7b72import T7ee787kotlinx.coroutines.delay
Tff7b72import T7ee787kotlinx.coroutines.flow.MutableStateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.StateFlow
Tff7b72import T7ee787kotlinx.coroutines.flow.asStateFlow
Tff7b72import T7ee787kotlinx.coroutines.launch
Tff7b72import T7ee787kotlinx.coroutines.withContext
Tff7b72import T7ee787org.meshtastic.core.di.CoroutineDispatchers
Tff7b72import T7ee787java.net.InetAddress
Tff7b72import T7ee787java.net.ServerSocket
Tff7b72import T7ee787java.net.Socket
Tff7b72import T7ee787java.util.concurrent.locks.ReentrantLock
Tff7b72import T7ee787javax.net.ssl.SSLServerSocket
Tff7b72import T7ee787kotlin.concurrent.Volatile
Tff7b72import T7ee787kotlin.concurrent.withLock
Tff7b72import T7ee787kotlin.random.Random
Tff7b72import T7ee787kotlinx.coroutines.isActive Tff7b72as Te6edf3coroutineIsActive

T8b949e/**
* JSSE-backed TLS TAK server. Matches the Meshtastic-Apple (iOS) implementation:
* - Binds `127.0.0.1:8089` (loopback only — no remote device can reach the server)
* - TLS 1.2+ with the bundled server.p12 identity
* - Mutual TLS: clients MUST present a certificate chaining to the bundled ca.pem
* - `SO_REUSEADDR` on the listen socket so an app restart doesn't hit `BindException: Address already in use` while the
* previous socket is in `TIME_WAIT`
* - Per-connection [TAKClientConnection] running on [CoroutineDispatchers.io]
*
* If the bundled certificates fail to load (e.g. packaging regression), the server refuses to start rather than
* silently falling back to plain TCP — that failure mode would produce exactly the symptom the user was debugging
* ("ATAK never connects").
*/
Tff7b72internal Tff7b72class T56d364TAKServerJvmTb4b4b4(Tff7b72private Tff7b72val Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4, Tff7b72private Tff7b72val Te6edf3portTb4b4b4: Tffa657Int Tff7b72= Te6edf3DEFAULT_TAK_PORTTb4b4b4) Tb4b4b4:
Te6edf3TAKServer Tb4b4b4{

Tff7b72private Tff7b72var Te6edf3serverSocketTb4b4b4: Te6edf3ServerSocket? Tff7b72= Tff7b72null

Tf0883e@Volatile Tff7b72private Tff7b72var Te6edf3running Tff7b72= Tff7b72false
Tff7b72private Tff7b72var Te6edf3serverScopeTb4b4b4: Te6edf3CoroutineScope? Tff7b72= Tff7b72null
Tff7b72private Tff7b72var Te6edf3acceptJobTb4b4b4: Te6edf3Job? Tff7b72= Tff7b72null
Tff7b72private Tff7b72val Te6edf3connectionsLock Tff7b72= Te6edf3ReentrantLockTb4b4b4(Tb4b4b4)
Tff7b72private Tff7b72val Te6edf3connections Tff7b72= Te6edf3mutableMapOfTff7b72<Tffa657StringTb4b4b4, Te6edf3TAKClientConnectionTff7b72>Tb4b4b4(Tb4b4b4)

Tff7b72private Tff7b72val Te6edf3_connectionCount Tff7b72= Te6edf3MutableStateFlowTb4b4b4(T79c0ff0Tb4b4b4)
Tff7b72override Tff7b72val Te6edf3connectionCountTb4b4b4: Te6edf3StateFlowTff7b72<Tffa657IntTff7b72> Tff7b72= Te6edf3_connectionCountTb4b4b4.Te6edf3asStateFlowTb4b4b4(Tb4b4b4)

Tff7b72override Tff7b72var Te6edf3onMessageTb4b4b4: Tb4b4b4(Tb4b4b4(Te6edf3CoTMessageTb4b4b4, Te6edf3TAKClientInfo?Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4)Tff7b72? Tff7b72= Tff7b72null
Tff7b72override Tff7b72var Te6edf3onClientConnectedTb4b4b4: Tb4b4b4(Tb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tffa657UnitTb4b4b4)Tff7b72? Tff7b72= Tff7b72null

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffstartTb4b4b4(Te6edf3scopeTb4b4b4: Te6edf3CoroutineScopeTb4b4b4)Tb4b4b4: Te6edf3ResultTff7b72<Tffa657UnitTff7b72> Tb4b4b4{
Tff7b72if Tb4b4b4(Te6edf3runningTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK Server already running on port Tffd700$Te6edf3portTa5d6ff" Tb4b4b4}
Tff7b72return Te6edf3ResultTb4b4b4.Te6edf3successTb4b4b4(Tffa657UnitTb4b4b4)
Tb4b4b4}

Tff7b72val Te6edf3sslContext Tff7b72=
Te6edf3TakCertLoaderTb4b4b4.Te6edf3getServerSslContextTb4b4b4(Tb4b4b4)
Tff7b72?: Tff7b72return Te6edf3ResultTb4b4b4.Te6edf3failureTb4b4b4(
Te6edf3IllegalStateExceptionTb4b4b4(
Ta5d6ff"Ta5d6ffTAK Server: bundled TLS certificates could not be loadedTa5d6ff" Tff7b72+ Ta5d6ff"Ta5d6ff; refusing to startTa5d6ff"Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Tff7b72return Tff7b72try Tb4b4b4{
Te6edf3serverScope Tff7b72= Te6edf3scope

T8b949e// Bind on the IO dispatcher — bind() can briefly block.
Tff7b72val Te6edf3boundSocket Tff7b72=
Te6edf3withContextTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3factory Tff7b72= Te6edf3sslContextTb4b4b4.Te6edf3serverSocketFactory
T8b949e// Use the address-specific overload so we bind to loopback only.
Tff7b72val Te6edf3loopback Tff7b72= Te6edf3InetAddressTb4b4b4.Te6edf3getByNameTb4b4b4(Ta5d6ff"Ta5d6ff127.0.0.1Ta5d6ff"Tb4b4b4)
T8b949e// backlog of 4 is plenty for local TAK clients
Tff7b72val Te6edf3tls Tff7b72= Te6edf3factoryTb4b4b4.Te6edf3createServerSocketTb4b4b4(Te6edf3portTb4b4b4, T79c0ff4Tb4b4b4, Te6edf3loopbackTb4b4b4) Tff7b72as Te6edf3SSLServerSocket
Te6edf3configureTlsServerSocketTb4b4b4(Te6edf3tlsTb4b4b4)
Te6edf3tls
Tb4b4b4}
Te6edf3serverSocket Tff7b72= Te6edf3boundSocket
Te6edf3running Tff7b72= Tff7b72true
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK Server listening on 127.0.0.1:Tffd700$Te6edf3portTa5d6ff (TLS, mTLS enforced)Ta5d6ff" Tb4b4b4}

Te6edf3acceptJob Tff7b72= Te6edf3scopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{ Te6edf3acceptLoopTb4b4b4(Tb4b4b4) Tb4b4b4}
Te6edf3ResultTb4b4b4.Te6edf3successTb4b4b4(Tffa657UnitTb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3eTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to bind TAK Server to 127.0.0.1:Tffd700$Te6edf3portTa5d6ff" Tb4b4b4}
Te6edf3running Tff7b72= Tff7b72false
Tff7b72try Tb4b4b4{
Te6edf3serverSocketTff7b72?.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3_Tb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{Tb4b4b4}
Te6edf3serverSocket Tff7b72= Tff7b72null
Te6edf3ResultTb4b4b4.Te6edf3failureTb4b4b4(Te6edf3eTb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffconfigureTlsServerSocketTb4b4b4(Te6edf3tlsTb4b4b4: Te6edf3SSLServerSocketTb4b4b4) Tb4b4b4{
T8b949e// Minimum TLS 1.2 — matches iOS.
Tff7b72val Te6edf3protocols Tff7b72= Te6edf3tlsTb4b4b4.Te6edf3supportedProtocolsTb4b4b4.Te6edf3filter Tb4b4b4{ Tffa657it Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ffTLSv1.2Ta5d6ff" Tff7b72|Tff7b72| Tffa657it Tff7b72=Tff7b72= Ta5d6ff"Ta5d6ffTLSv1.3Ta5d6ff" Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3protocolsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3tlsTb4b4b4.Te6edf3enabledProtocols Tff7b72= Te6edf3protocolsTb4b4b4.Te6edf3toTypedArrayTb4b4b4(Tb4b4b4)
Tb4b4b4}
T8b949e// Require client certificate (mTLS) — matches
T8b949e// `sec_protocol_options_set_peer_authentication_required` on iOS.
Te6edf3tlsTb4b4b4.Te6edf3needClientAuth Tff7b72= Tff7b72true
T8b949e// Enable address reuse so restart doesn't hit TIME_WAIT on the port.
Te6edf3tlsTb4b4b4.Te6edf3reuseAddress Tff7b72= Tff7b72true
Tb4b4b4}

Tff7b72private Tff7b72suspend Tff7b72fun Td2a8ffacceptLoopTb4b4b4(Tb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3scope Tff7b72= Te6edf3serverScope Tff7b72?: Tff7b72return
Tff7b72while Tb4b4b4(Te6edf3running Tff7b72&Tff7b72& Te6edf3scopeTb4b4b4.Te6edf3coroutineIsActiveTb4b4b4) Tb4b4b4{
Tff7b72try Tb4b4b4{
Tff7b72val Te6edf3clientSocket Tff7b72= Te6edf3withContextTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{ Te6edf3serverSocketTff7b72?.Te6edf3acceptTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3clientSocket Tff7b72!Tff7b72= Tff7b72nullTb4b4b4) Tb4b4b4{
Te6edf3handleConnectionTb4b4b4(Te6edf3clientSocketTb4b4b4)
Tb4b4b4}
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3CancellationExceptionTb4b4b4) Tb4b4b4{
Tff7b72throw Te6edf3e
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
T8b949e// Bind was lost or the socket was closed under us — back off, then retry.
Tff7b72if Tb4b4b4(Te6edf3runningTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK server accept loop iteration failed: Tffd700${Te6edf3eTb4b4b4.Te6edf3messageTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Te6edf3delayTb4b4b4(Te6edf3TAK_ACCEPT_LOOP_DELAY_MSTb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffhandleConnectionTb4b4b4(Te6edf3clientSocketTb4b4b4: Te6edf3SocketTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3scope Tff7b72= Te6edf3serverScope Tff7b72?: Tff7b72return
Tff7b72val Te6edf3endpoint Tff7b72= Te6edf3clientSocketTb4b4b4.Te6edf3remoteSocketAddressTff7b72?.Te6edf3toStringTb4b4b4(Tb4b4b4) Tff7b72?: Ta5d6ff"Ta5d6ffunknownTa5d6ff"

Tff7b72if Tb4b4b4(Te6edf3clientSocketTb4b4b4.Te6edf3inetAddressTff7b72?.Te6edf3isLoopbackAddress Tff7b72!Tff7b72= Tff7b72trueTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3w Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK server rejected non-loopback connection from Tffd700$Te6edf3endpointTa5d6ff" Tb4b4b4}
Tff7b72try Tb4b4b4{
Te6edf3clientSocketTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3_Tb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{Tb4b4b4}
Tff7b72return
Tb4b4b4}

Tff7b72val Te6edf3connectionId Tff7b72= Te6edf3RandomTb4b4b4.Te6edf3nextIntTb4b4b4(Tb4b4b4)Tb4b4b4.Te6edf3toStringTb4b4b4(Te6edf3TAK_HEX_RADIXTb4b4b4)
Tff7b72val Te6edf3clientInfo Tff7b72= Te6edf3TAKClientInfoTb4b4b4(Te6edf3id Tff7b72= Te6edf3connectionIdTb4b4b4, Te6edf3endpoint Tff7b72= Te6edf3endpointTb4b4b4)
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK client connected: id=Tffd700$Te6edf3connectionIdTa5d6ff endpoint=Tffd700$Te6edf3endpointTa5d6ff" Tb4b4b4}

Tff7b72val Te6edf3connection Tff7b72=
Te6edf3TAKClientConnectionTb4b4b4(
Te6edf3socket Tff7b72= Te6edf3clientSocketTb4b4b4,
Te6edf3clientInfo Tff7b72= Te6edf3clientInfoTb4b4b4,
Te6edf3onEvent Tff7b72= Tb4b4b4{ Te6edf3event Tff7b72-Tff7b72> Te6edf3handleConnectionEventTb4b4b4(Te6edf3connectionIdTb4b4b4, Te6edf3eventTb4b4b4) Tb4b4b4}Tb4b4b4,
Te6edf3scope Tff7b72= Te6edf3scopeTb4b4b4,
Te6edf3ioDispatcher Tff7b72= Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4,
Tb4b4b4)

T8b949e// Launch on IO so socket reads/writes don't queue behind CPU work on Default
Te6edf3scopeTb4b4b4.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{
Te6edf3connectionsTff7b72[Te6edf3connectionIdTff7b72] Tff7b72= Te6edf3connection
Te6edf3_connectionCountTb4b4b4.Te6edf3value Tff7b72= Te6edf3connectionsTb4b4b4.Te6edf3size
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK connection count now Tffd700${Te6edf3connectionsTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Te6edf3connectionTb4b4b4.Te6edf3startTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}

Tff7b72private Tff7b72fun Td2a8ffhandleConnectionEventTb4b4b4(Te6edf3connectionIdTb4b4b4: Tffa657StringTb4b4b4, Te6edf3eventTb4b4b4: Te6edf3TAKConnectionEventTb4b4b4) Tb4b4b4{
Tff7b72when Tb4b4b4(Te6edf3eventTb4b4b4) Tb4b4b4{
Tff7b72is Te6edf3TAKConnectionEventTb4b4b4.Te6edf3Message Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3onMessageTff7b72?.Te6edf3invokeTb4b4b4(Te6edf3eventTb4b4b4.Te6edf3cotMessageTb4b4b4, Te6edf3eventTb4b4b4.Te6edf3clientInfoTb4b4b4)
Tb4b4b4}

Tff7b72is Te6edf3TAKConnectionEventTb4b4b4.Te6edf3Disconnected Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK client disconnected: id=Tffd700$Te6edf3connectionIdTa5d6ff" Tb4b4b4}
Te6edf3serverScopeTff7b72?.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{
Te6edf3connectionsTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3connectionIdTb4b4b4)
Te6edf3_connectionCountTb4b4b4.Te6edf3value Tff7b72= Te6edf3connectionsTb4b4b4.Te6edf3size
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK connection count now Tffd700${Te6edf3connectionsTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72is Te6edf3TAKConnectionEventTb4b4b4.Te6edf3Error Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eventTb4b4b4.Te6edf3errorTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK client connection error: Tffd700$Te6edf3connectionIdTa5d6ff" Tb4b4b4}
Te6edf3serverScopeTff7b72?.Te6edf3launchTb4b4b4(Te6edf3dispatchersTb4b4b4.Te6edf3ioTb4b4b4) Tb4b4b4{
Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{
Te6edf3connectionsTb4b4b4.Te6edf3removeTb4b4b4(Te6edf3connectionIdTb4b4b4)
Te6edf3_connectionCountTb4b4b4.Te6edf3value Tff7b72= Te6edf3connectionsTb4b4b4.Te6edf3size
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK connection count now Tffd700${Te6edf3connectionsTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff" Tb4b4b4}
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72is Te6edf3TAKConnectionEventTb4b4b4.Te6edf3Connected Tff7b72-Tff7b72> Tb4b4b4{
Te6edf3onClientConnectedTff7b72?.Te6edf3invokeTb4b4b4(Tb4b4b4)
Tb4b4b4}

Tff7b72is Te6edf3TAKConnectionEventTb4b4b4.Te6edf3ClientInfoUpdated Tff7b72-Tff7b72> Tb4b4b4{
T8b949e/* no-op: TAKClientConnection tracks updated info locally */
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72fun Td2a8ffstopTb4b4b4(Tb4b4b4) Tb4b4b4{
Te6edf3running Tff7b72= Tff7b72false
Te6edf3acceptJobTff7b72?.Te6edf3cancelTb4b4b4(Tb4b4b4)
Te6edf3acceptJob Tff7b72= Tff7b72null

T8b949e// Guard the snapshot+clear with the same lock used by the coroutine accept/disconnect
T8b949e// paths to avoid concurrent modification or a stale connectionCount during shutdown.
Tff7b72val Te6edf3toClose Tff7b72=
Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{
Tff7b72val Te6edf3snapshot Tff7b72= Te6edf3connectionsTb4b4b4.Te6edf3valuesTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4)
Te6edf3connectionsTb4b4b4.Te6edf3clearTb4b4b4(Tb4b4b4)
Te6edf3_connectionCountTb4b4b4.Te6edf3value Tff7b72= T79c0ff0
Te6edf3snapshot
Tb4b4b4}
Te6edf3toCloseTb4b4b4.Te6edf3forEach Tb4b4b4{ Tffa657itTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4) Tb4b4b4}

Tff7b72try Tb4b4b4{
Te6edf3serverSocketTff7b72?.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3_Tb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{Tb4b4b4}
Te6edf3serverSocket Tff7b72= Tff7b72null
Te6edf3serverScope Tff7b72= Tff7b72null
Te6edf3LoggerTb4b4b4.Te6edf3i Tb4b4b4{ Ta5d6ff"Ta5d6ffTAK Server stoppedTa5d6ff" Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffbroadcastTb4b4b4(Te6edf3cotMessageTb4b4b4: Te6edf3CoTMessageTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentConnections Tff7b72= Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{ Te6edf3connectionsTb4b4b4.Te6edf3valuesTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3currentConnectionsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffbroadcast Tffd700${Te6edf3cotMessageTb4b4b4.Te6edf3typeTffd700}Ta5d6ff: no TAK clients connected, droppingTa5d6ff" Tb4b4b4}
Tff7b72return
Tb4b4b4}
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffbroadcast Tffd700${Te6edf3cotMessageTb4b4b4.Te6edf3typeTffd700}Ta5d6ff to Tffd700${Te6edf3currentConnectionsTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff TAK client(s)Ta5d6ff" Tb4b4b4}
Te6edf3currentConnectionsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3connection Tff7b72-Tff7b72>
Tff7b72try Tb4b4b4{
Te6edf3connectionTb4b4b4.Te6edf3sendTb4b4b4(Te6edf3cotMessageTb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to broadcast CoT to TAK client Tffd700${Te6edf3connectionTb4b4b4.Te6edf3clientInfoTb4b4b4.Te6edf3idTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3connectionTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffbroadcastRawXmlTb4b4b4(Te6edf3xmlTb4b4b4: Tffa657StringTb4b4b4) Tb4b4b4{
Tff7b72val Te6edf3currentConnections Tff7b72= Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{ Te6edf3connectionsTb4b4b4.Te6edf3valuesTb4b4b4.Te6edf3toListTb4b4b4(Tb4b4b4) Tb4b4b4}
Tff7b72if Tb4b4b4(Te6edf3currentConnectionsTb4b4b4.Te6edf3isEmptyTb4b4b4(Tb4b4b4)Tb4b4b4) Tff7b72return
Te6edf3LoggerTb4b4b4.Te6edf3d Tb4b4b4{ Ta5d6ff"Ta5d6ffbroadcastRawXml to Tffd700${Te6edf3currentConnectionsTb4b4b4.Te6edf3sizeTffd700}Ta5d6ff TAK client(s)Ta5d6ff" Tb4b4b4}
Te6edf3currentConnectionsTb4b4b4.Te6edf3forEach Tb4b4b4{ Te6edf3connection Tff7b72-Tff7b72>
Tff7b72try Tb4b4b4{
Te6edf3connectionTb4b4b4.Te6edf3sendRawXmlTb4b4b4(Te6edf3xmlTb4b4b4)
Tb4b4b4} Tff7b72catch Tb4b4b4(Te6edf3eTb4b4b4: Te6edf3ExceptionTb4b4b4) Tb4b4b4{
Te6edf3LoggerTb4b4b4.Te6edf3wTb4b4b4(Te6edf3eTb4b4b4) Tb4b4b4{ Ta5d6ff"Ta5d6ffFailed to broadcast raw XML to TAK client Tffd700${Te6edf3connectionTb4b4b4.Te6edf3clientInfoTb4b4b4.Te6edf3idTffd700}Ta5d6ff" Tb4b4b4}
Te6edf3connectionTb4b4b4.Te6edf3closeTb4b4b4(Tb4b4b4)
Tb4b4b4}
Tb4b4b4}
Tb4b4b4}

Tff7b72override Tff7b72suspend Tff7b72fun Td2a8ffhasConnectionsTb4b4b4(Tb4b4b4)Tb4b4b4: Tffa657Boolean Tff7b72= Te6edf3connectionsLockTb4b4b4.Te6edf3withLock Tb4b4b4{ Te6edf3connectionsTb4b4b4.Te6edf3isNotEmptyTb4b4b4(Tb4b4b4) Tb4b4b4}
Tb4b4b4}

T8b949e/**
* `actual` factory for the KMP `expect fun createTAKServer` declared in `commonMain`. Both the Desktop JVM target and
* the Android target share this source set, so both run the same JSSE-based TLS listener.
*
* Also wires [TAKDataPackageGenerator]'s bundled-cert provider so that the exported `.zip` data package contains the
* real `server.p12` / `client.p12` bytes from the classpath rather than an empty fallback.
*/
Tff7b72actual Tff7b72fun Td2a8ffcreateTAKServerTb4b4b4(Te6edf3dispatchersTb4b4b4: Te6edf3CoroutineDispatchersTb4b4b4, Te6edf3portTb4b4b4: Tffa657IntTb4b4b4)Tb4b4b4: Te6edf3TAKServer Tb4b4b4{
Te6edf3TAKDataPackageGeneratorTb4b4b4.Te6edf3bundledCertBytesProvider Tff7b72= Te6edf3TakCertBundledBytesProvider
Tff7b72return Te6edf3TAKServerJvmTb4b4b4(Te6edf3dispatchers Tff7b72= Te6edf3dispatchersTb4b4b4, Te6edf3port Tff7b72= Te6edf3portTb4b4b4)
Tb4b4b4}

T8b949e/** Bridges [TakCertLoader] bytes into [TAKDataPackageGenerator] via the commonMain interface. */
Tff7b72private Tff7b72object T56d364TakCertBundledBytesProvider Tb4b4b4: Te6edf3BundledCertBytesProvider Tb4b4b4{
Tff7b72override Tff7b72fun Td2a8ffserverP12BytesTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3ByteArray? Tff7b72= Te6edf3TakCertLoaderTb4b4b4.Te6edf3getServerP12BytesTb4b4b4(Tb4b4b4)

Tff7b72override Tff7b72fun Td2a8ffclientP12BytesTb4b4b4(Tb4b4b4)Tb4b4b4: Te6edf3ByteArray? Tff7b72= Te6edf3TakCertLoaderTb4b4b4.Te6edf3getClientP12BytesTb4b4b4(Tb4b4b4)
Tb4b4b4}

Served by rngit 1.5.0 - Generated in 0.08s